class Compile {
    constructor(el, vm) {
        this.el = el
        this.vm = vm
        this.reg = /\{\{([^}]*)\}\}/g
        // @ 1 : 放入虚拟dom
        let fragment = this.node2fragment(this.el)
        // @ 2 : 渲染数据
        this.compile(fragment)
        // @ 3 : 移出虚拟dom
        this.fragment2node(this.el, fragment)
    }
    // 核心方法============================================================================
    // 放入虚拟dom, 详情查看 : 02_07_
    node2fragment(el) {
        let fragment = document.createDocumentFragment()
        let first_child
        while (first_child=el.firstChild) {
            fragment.appendChild(first_child)
        }
        return fragment
    }
    // 移出虚拟dom, 详情查看 : 02_07_
    fragment2node(el, fragment) {
        el.appendChild(fragment)
    }
    // 编译模版
    compile(fragment) {
        this.for_earch(fragment, node=>{
            if      (node.nodeType===1) this.compile_element(node)
            else if (node.nodeType===3) this.compile_text(node) 
        })
    }
    // 编译元素节点
    compile_element(node) {
        node.getAttributeNames().map(v_name=>{
            if(v_name.substr(0,2)==='v-'){ // 如果是 v- 开头的字符串, 涉及基础知识 : 01_10_
                let name = v_name.substr(2) // 如果: v_name="v-model" 那么: name='model'
                let expr = node.getAttribute(v_name) // 如果: v-model="jack.name" 那么: expr='jack.name', 涉及基础知识: 01_09_ 
                let has = this[`render_v_${name}`]
                if (has) {
                    // @ 1 : 渲染该节点
                    this[`render_v_${name}`](node, this.vm, expr) // 如果方法存在就执行
                    // @ 2 : 为该节点生成一个watcher
                    new Wathcer(this.vm, expr, ()=>{
                        this[`render_v_${name}`](node, this.vm, expr)
                    })
                    // @ 3 : 给 'v-mode' 绑定 'input' 事件
                    name==='model' && node.addEventListener('input',e=>{
                        let value = e.target.value
                        console.log(value)
                        this.set_value(vm, expr, value)
                    })
                }
            }
        })
    }
    // 编译文本节点
    compile_text(node) {
        let has_brace = this.has_brace(node)
        if(has_brace) {
            // @ 1 : 保存模版
            node.template = node.data
            // @ 2 : 渲染节点
            this.render_text(node, this.vm)
            // @ 3 : 如果该节点绑定了a和b连个数据, 那么就为该节点生成两个watcher, 分别发送到list_a,list_b中
            node.template.replace(this.reg, (x, y)=>{
                new Wathcer(this.vm, y, ()=>this.render_text(node, this.vm))
            })
        }
    }
    // 渲染文本节点
    render_text(node, vm) {
        node.data = node.template.replace(this.reg, (x,y)=>this.get_value(vm.$data, y)) // 涉及知识点 : 01_15_
    }
    // 渲染有 v-model 的元素节点
    render_v_model(node, vm, expr) {
        let value = this.get_value(vm.$data, expr)
        node.value = value
    }
    // 渲染 v-text 的元素节点
    render_v_text(node, vm, expr) {
        let value = this.get_value(vm.$data, expr)
        node.innerHTML = value
    }
    // 辅助方法============================================================================
    // 遍历每一个子孙节点, 并使用回调进行处理, 详情查看 : 02_08_
    for_earch(dom, cb) {
        Array.from(dom.childNodes).map(node=>{
            cb(node)
            let has_children = node.childNodes.length?true:false
            if(has_children) this.for_earch(node, cb)
        })
    }
    // 已知expr="jack.father.name", 获取值this.$data['jack']['father']['name'], 详情查看 : 02_09_
    get_value(data, expr) {
        return expr.split('.').reduce((y, item)=>y[item], data)
    }
    // 已知expr='jack.father.name', 赋值this.$data['jack']['father']['name']=new_v, 详情查看 : 02_10_
    set_value(data, expr, new_v) {
        let arr = expr.split('.')
        return arr.reduce((y, item, index)=>{
            if (index===arr.length-1) return y[item]=new_v
            else return y[item]
        }, data)
    }
    // 检查文本节点是否有双大括号 {{...}}, 详情查看 : 01_16_
    has_brace(node) {
        return this.reg.test(node.data)
    }
}